package com.second.app.thread.线程基础.day04.block;

import java.util.ArrayList;
import java.util.List;

/**
 * @Author GYZ
 * @Date 2023/11/22
 * <pre>
 *  案例1：主要分析两个线程执行synchronized方法代码块，执行耗时。
 *         由此引出效率问题
 *         由同步整个方法，变成同步代码块
 *         解决方案：同步代码块。
 *  案例2：一半异步，一半同步
 *        根据控制台打印，执行普通方法可以发现，线程是 交替打印
 *        但是同步方法后，则排队执行。
 *  案例3：代码块间的同步性
 *        当一个线程访问object的一个synchronized(this)同步代码块时，其他线程对同一个object中
 *        所有其他synchronized(this)同步代码块的访问将被阻塞，这说明synchronized使用的”对象监视器“是一个
 *        两个同步代码块是按顺序执行的
 *  案例4：验证同步synchronized(this)代码块是锁定当前对象的
 *
 *  将任意对象作为对象监视器
 *        多个线程调用同一个对象中的不同名称的synchronized同步方法或synchronized(this)同步代码块时
 *        调用效果就是按顺序执行，也就是同步，阻塞的。
 *
 *   synchronized(this对象)
 *   synchronized(非this对象)
 *   锁非this对象具有一定的优点：如果在一个类中有很多synchronized方法，这时候虽然能实现同步，但会受到阻塞
 *   所以影响运行效率；但是如果使用同步代码块锁非this对象，则synchronized(非this)代码块中的程序与同步方法
 *   是异步的。不和其他锁this同步方法争抢this锁，则可大大提高运行效率。
 *
 *   案例5：从运行结果来看，同步块中的代码是同步打印的。当前线程的”执行“和”退出“是成对出现的，但是线程A和线程B执行却是
 *         异步的。所以可能出现脏读的情况。(见案例6)
 *
 *   案例6：两个线程往list集合中添加元素。前提条件：如果集合中的元素数量小于1，则添加。
 *         但是最终获取list的元素个数为2。所以出现了脏读现象。
 *         解决方法：加上synchronized(this)同步代码块
 *
 *
 * </pre>
 */

//案例6
class MyOneList {
    private List list = new ArrayList();

    synchronized public void add(String data) {
        list.add(data);
    }

    synchronized public int getSize() {
        return list.size();
    }
}

//案例6
class MyService {
    public MyOneList addServiceMethod(MyOneList list, String data) {
        try {
            synchronized (list) {
                if (list.getSize() < 1) {
                    Thread.sleep(2000);
                    list.add(data);
                }
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return list;
    }
}

//案例6
class Demo6 {
    public static void main(String[] args) {
        class ThreadU1 extends Thread {
            private MyOneList myOneList;

            public ThreadU1(MyOneList myOneList) {
                this.myOneList = myOneList;
            }

            @Override
            public void run() {
                MyService msRef = new MyService();
                msRef.addServiceMethod(myOneList, "A");
            }
        }

        class ThreadU2 extends Thread {
            private MyOneList myOneList;

            public ThreadU2(MyOneList myOneList) {
                this.myOneList = myOneList;
            }

            @Override
            public void run() {
                MyService msRef = new MyService();
                msRef.addServiceMethod(myOneList, "B");

            }
        }
        try {
            MyOneList myOneList = new MyOneList();

            ThreadU1 threadU1 = new ThreadU1(myOneList);
            threadU1.setName("A");
            threadU1.start();

            ThreadU2 threadU2 = new ThreadU2(myOneList);
            threadU2.setName("B");
            threadU2.start();

            Thread.sleep(6000);

            System.out.println("listSize=" + myOneList.getSize());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}


//案例5
class MyList {

    private List list = new ArrayList();

    synchronized public void add(String userName) {
        System.out.println("ThreadName=" + Thread.currentThread().getName() + "执行了add方法!");
        list.add(userName);
        System.out.println("ThreadName=" + Thread.currentThread().getName() + "退出了add方法!");
    }

    synchronized public int getSize() {
        System.out.println("ThreadName=" + Thread.currentThread().getName() + "执行了getSize方法!");
        int sizeValue = list.size();
        System.out.println("ThreadName=" + Thread.currentThread().getName() + "退出了getSize方法!");
        return sizeValue;
    }
}

class Demo5 {
    public static void main(String[] args) {
        class MyThread001 extends Thread {
            private MyList myList;

            public MyThread001(MyList myList) {
                this.myList = myList;
            }

            @Override
            public void run() {
                for (int i = 0; i < 100000; i++) {
                    myList.add("threadA" + (i + 1));
                }
            }
        }

        class MyThread002 extends Thread {
            private MyList myList;

            public MyThread002(MyList myList) {
                this.myList = myList;
            }

            @Override
            public void run() {
                for (int i = 0; i < 100000; i++) {
                    myList.add("threadB" + (i + 1));
                }
            }
        }
        MyList myList = new MyList();
        MyThread001 myThread001 = new MyThread001(myList);
        myThread001.setName("A");
        myThread001.start();

        MyThread002 myThread002 = new MyThread002(myList);
        myThread002.setName("B");
        myThread002.start();
    }
}

//案例3
class ObjectService {
    public void serviceMethodA() {
        synchronized (this) {
            try {
                System.out.println("A begin time=" + System.currentTimeMillis());
                Thread.sleep(2000);
                System.out.println("A end    end=" + System.currentTimeMillis());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public void serviceMethodB() {
        synchronized (this) {
            System.out.println("B begin time=" + System.currentTimeMillis());
            System.out.println("B end    end=" + System.currentTimeMillis());
        }
    }
}

//案例3
class TestDemo3 {
    public static void main(String[] args) {
        class XXThread extends Thread {
            private ObjectService objectService;

            public XXThread(ObjectService objectService) {
                this.objectService = objectService;
            }

            @Override
            public void run() {
                objectService.serviceMethodA();
            }
        }
        class YYThread extends Thread {
            private ObjectService objectService;

            public YYThread(ObjectService objectService) {
                this.objectService = objectService;
            }

            @Override
            public void run() {
                objectService.serviceMethodB();
            }
        }

        ObjectService objectService = new ObjectService();
        XXThread xxThread = new XXThread(objectService);
        xxThread.setName("a");
        xxThread.start();

        YYThread yyThread = new YYThread(objectService);
        yyThread.setName("b");
        yyThread.start();
    }
}


//案例2
class Task2 {
    public void doLongTimeTask() {
        for (int i = 0; i < 100; i++) {
            System.out.println("nonSynchronized threadName=" + Thread.currentThread().getName() + " i=" + (i + 1));
        }
        System.out.println("");

        synchronized (this) {
            for (int i = 0; i < 100; i++) {
                System.out.println("synchronized threadName=" + Thread.currentThread().getName() + " i=" + (i + 1));
            }
        }
    }

}

class Test2 {
    public static void main(String[] args) {
        class Thread02 extends Thread {
            public Task2 task2;

            public Thread02(Task2 task2) {
                this.task2 = task2;
            }

            @Override
            public void run() {
                task2.doLongTimeTask();
            }
        }
        class Thread03 extends Thread {
            public Task2 task2;

            public Thread03(Task2 task2) {
                this.task2 = task2;
            }

            @Override
            public void run() {
                task2.doLongTimeTask();
            }
        }
        Task2 task2 = new Task2();
        Thread02 thread02 = new Thread02(task2);
        thread02.start();
        Thread03 thread03 = new Thread03(task2);
        thread03.start();
    }
}


//案例1
public class Task {

    private String getData1;

    private String getData2;

    synchronized public void doLongTimeTask() {
        try {
            System.out.println("begin task");
            Thread.sleep(3000);
            getData1 = "长时间处理任务后从远程返回的值 1 threadName=" + Thread.currentThread().getName();
            getData2 = "长时间处理任务后从远程返回的值 2 threadName=" + Thread.currentThread().getName();
            System.out.println(getData1);
            System.out.println(getData2);
            System.out.println("end task");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

class CommonUtils {
    public static long beginTime1;

    public static long endTime1;

    public static long beginTime2;

    public static long endTime2;

}

class TestDemo {
    public static void main(String[] args) {
        class MyThread1 extends Thread {
            private Task task;

            public MyThread1(Task task) {
                this.task = task;
            }

            @Override
            public void run() {
                CommonUtils.beginTime1 = System.currentTimeMillis();
                task.doLongTimeTask();
                CommonUtils.endTime1 = System.currentTimeMillis();
            }
        }
        class MyThread2 extends Thread {
            private Task task;

            public MyThread2(Task task) {
                this.task = task;
            }

            @Override
            public void run() {
                CommonUtils.beginTime2 = System.currentTimeMillis();
                task.doLongTimeTask();
                CommonUtils.endTime2 = System.currentTimeMillis();
            }
        }
        //
        Task task = new Task();
        MyThread1 myThread1 = new MyThread1(task);
        myThread1.start();
        MyThread2 myThread2 = new MyThread2(task);
        myThread2.start();
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        long beginTime = CommonUtils.beginTime1;

        if (CommonUtils.beginTime2 < CommonUtils.beginTime1) {
            beginTime = CommonUtils.beginTime2;
        }
        long endTime = CommonUtils.endTime1;

        if (CommonUtils.endTime2 > CommonUtils.endTime1) {
            endTime = CommonUtils.endTime2;
        }
        System.out.println("耗时：" + (endTime - beginTime) / 1000);
    }
}
